﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using Autofac;
using FlowBasis.Web.Autofac;

namespace FlowBasisSampleSite
{

    public class MvcApplication : System.Web.HttpApplication
    {
        private static IContainer s_rootAutofacContainer;
        private static HttpRequestServiceResolverProvider s_httpRequestServiceResolverProvider;



        public static void RegisterGlobalFilters(GlobalFilterCollection filters)
        {
            filters.Add(new HandleErrorAttribute());
        }

        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            routes.MapRoute(
                "Default", // Route name
                "{controller}/{action}/{id}", // URL with parameters
                new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
            );

        }

        protected void Application_Start()
        {
            InitializeServiceResolvers();

            ValueProviderFactories.Factories.Add(new FlowBasis.Web.Mvc.PostRpcValueProviderFactory());
            ModelBinders.Binders.DefaultBinder = new FlowBasis.Web.Mvc.PostRpcModelBinder(ModelBinders.Binders.DefaultBinder);

            AreaRegistration.RegisterAllAreas();

            RegisterGlobalFilters(GlobalFilters.Filters);
            RegisterRoutes(RouteTable.Routes);
        }

        protected void Application_Error(object sender, EventArgs e)
        {
            Exception lastError = Server.GetLastError();

            // TODO: Log lastError.            
        }

        protected void Application_AuthenticateRequest(object sender, EventArgs e)
        {
            if (Context.User != null && Context.User.Identity != null && Context.User.Identity.IsAuthenticated)
            {
                Context.User = FlowBasisSampleSite.Lib.Security.FlowBasisSampleSitePrincipal.FromIdentity(Context.User.Identity);
            }
        }

        protected void Application_BeginRequest(object sender, EventArgs e)
        {
        }

        protected void Application_EndRequest(object sender, EventArgs e)
        {
            s_httpRequestServiceResolverProvider.DisposeLifetimeScopeResolverForRequest();
        }




        private void InitializeServiceResolvers()
        {
            var builder = new ContainerBuilder();

            // Register json mappings.
            FlowBasis.Json.DefaultJObjectMapperProvider jObjectMapperProvider = new FlowBasis.Json.DefaultJObjectMapperProvider();
            builder.RegisterInstance(jObjectMapperProvider).As<FlowBasis.Json.IJObjectMapperProvider>();

            // Register basic services.
            builder.RegisterType<FlowBasis.Web.Services.HttpContextService>().As<FlowBasis.Web.Services.IHttpContextService>();
            builder.RegisterType<FlowBasis.Web.Configuration.AppSettingsService>().As<FlowBasis.Configuration.IAppSettingsService>();
            builder.RegisterType<FlowBasis.Web.Configuration.JavascriptSettingsService>().As<FlowBasis.Web.Configuration.IJavascriptSettingsService>();
            builder.RegisterType<FlowBasis.Json.JObjectRootMapper>().As<FlowBasis.Json.IJObjectRootMapper>();
            builder.RegisterType<FlowBasis.Json.JsonSerializationService>().As<FlowBasis.Json.IJsonSerializationService>();

            // Authentication.
            builder.RegisterType<FlowBasis.Web.Security.HttpUserContextService>().As<FlowBasis.Security.IUserContextService>();
            builder.RegisterType<FlowBasis.Security.Passwords.Sha512PasswordValidationService>().As<FlowBasis.Security.Passwords.IHashedPasswordValidationService>();
            builder.RegisterType<FlowBasisSampleSite.Lib.Security.FormsAuthenticationService>().As<FlowBasis.Web.Security.IFormsAuthenticationService>();
            builder.RegisterType<FlowBasisSampleSite.Lib.Security.PasswordResetService>().As<FlowBasisSampleSite.Lib.Security.PasswordResetService>();

            // Register data services.
            var entityFrameworkMetadataService = new FlowBasis.EntityFramework.EntityFrameworkMetadataService(
                () => new FlowBasisSampleSite.Domain.DomainContext(),
                new Type[]
                {
                    // TODO: Allow for auto-discovery of entity types.
                    typeof(FlowBasisSampleSite.Domain.Entities.UserAccount),
                    typeof(FlowBasisSampleSite.Domain.Entities.Role),
                    typeof(FlowBasisSampleSite.Domain.Entities.Permission),
                });

            var entityFrameworkPrimaryKeyService = new FlowBasis.EntityFramework.EntityFrameworkPrimaryKeyService(entityFrameworkMetadataService);

            builder.RegisterInstance(entityFrameworkPrimaryKeyService).As<FlowBasis.Data.IEntityPrimaryKeyService>();

            builder.RegisterType<FlowBasisSampleSite.Domain.DomainContext>().As<System.Data.Entity.DbContext>().InstancePerDependency();
            builder.RegisterType<FlowBasis.EntityFramework.EntityFrameworkDataService>().As<FlowBasis.Data.IDataService>().InstancePerLifetimeScope();
            builder.RegisterType<FlowBasis.EntityFramework.EntityFrameworkUnitOfWork>().As<FlowBasis.Data.IUnitOfWork>().InstancePerDependency();

            // Register all controllers.
            foreach (var type in typeof(MvcApplication).Assembly.GetTypes())
            {
                if (typeof(Controller).IsAssignableFrom(type))
                {
                    builder.RegisterType(type).AsSelf();
                }
            }

            s_rootAutofacContainer = builder.Build();
            s_httpRequestServiceResolverProvider = new HttpRequestServiceResolverProvider(s_rootAutofacContainer);
            FlowBasis.Services.ServiceResolver.SetProvider(s_httpRequestServiceResolverProvider.GetLifetimeScopeResolverForRequest);

            var mvcDependencyResolver = new FlowBasis.Web.Mvc.FlowBasisDependencyResolver();
            System.Web.Mvc.DependencyResolver.SetResolver(mvcDependencyResolver);
        }
    }
}